<?php

namespace app\service;

use app\exception\ErrnoPlus;
use app\model\DeviceBaseModel;
use share\service\cache\CommonCacheKeyService;
use share\exception\ApiException;
use share\service\AmqpService;
use share\service\BaseModelService;
use share\service\IdMakerService;
use share\service\UserBaseService;
use share\service\MQService;
use share\service\NotifyDingTalkService;
use share\service\RedisLockService;
use share\utils\Helper;

class DeviceBaseService extends BaseModelService
{
    public static function getModel()
    {
        return new DeviceBaseModel();
    }

    /**
     * 编辑条目 新增或者修改
     */
    public static function edit($info)
    {
        $id = $info['id'];
        unset($info['id']);
        if ($id == 0) {
            $id = IdMakerService::make(IdMakerService::NAME_OF_DEVICE_BASE);
            $info['id'] = $id;
            //$info['pid'] = 0;
            self::addDeviceBase($info);
        } else {
            self::updateDeviceBase($id, $info);
        }
        //TODO add code here after data change
        return $info;
    }

    /**
     * 新增条目
     */
    public static function addDeviceBase($info)
    {
        self::add($info);
    }

    /**
     * 修改条目
     */
    public static function updateDeviceBase($id, $info)
    {
        $origin  = self::getBase($id);
        if (empty($origin)) {
            throw new ApiException("origin data is not exists", ErrnoPlus::COMMON_INVALID_INPUT);
        }
        //TODO  add code here
        self::update($id, $info);
    }

    public static function getByDn($dn, $filter = [])
    {
        if (empty($filter)) {
            $filter = [];
        }
        $filter['dn'] = $dn;
        return self::getByFilter($filter);
    }

    public static function getBySn($sn, $filter = [])
    {
        if (empty($filter)) {
            $filter = [];
        }
        $filter['serial_no'] = $sn;
        return self::getByFilter($filter);
    }

    /**
     * 根据序列号获取云存可用的设备
     */
    public static function getUsefulOssSn($sn){
        $filter  = [
            'serial_no' => $sn,
            // 'pid' => 0,
            'iot_id' => ['notnull','']
        ];
        return self::getByFilter($filter);
    }

    public static function getAllByDn($dn, $filter = [])
    {
        if (empty($filter)) {
            $filter = [];
        }
        $filter['dn'] = $dn;
        return self::getAllByFilter($filter);
    }

    public static function getAllChildren($pid)
    {
        //$filter['pid'] = $pid;
        return DeviceBaseChildService::getAllByPid($pid);
    }

    /**
     * 通过mqtt 修改设备基本信息
     */
    public static function upsetByPkDnMqtt($params){
        $dn = $params['dn'];
        $pk = $params['pk'];
        $iotId = $params['iot_id'];
        $serverSite = isset($params['server_site']) ? $params['server_site'] : '';
        $updateData = [  
            'iot_id' => $iotId,
        ];
        if(!empty($serverSite)){
            $updateData['server_site'] = $serverSite;
        }
        $lockName = CommonCacheKeyService::getCacheKey(CommonCacheKeyService::CACHE_KEY_LOCK_OF_DEVICE_BASE, ['dn' => $dn]);
        if (!RedisLockService::getLock($lockName)) {
            throw new ApiException("请勿频繁操作 upsetDevice:" . $dn, ErrnoPlus::LOCKED_IS_EXISTS);
        }
        $origin = self::getByDn($dn,[
            'pk' => $pk,
        ]);

        $id = 0;
        if ($origin) { // 设备已存在
            $id = $origin['id'];
            $isNeedUpdate = false;
            $keys = array_keys($updateData);
            foreach($keys as $key){
                if($origin[$key] != $updateData[$key]){
                    $isNeedUpdate = true;
                    break;
                }
            }
            if($isNeedUpdate){
                self::update($id,$updateData); 
            }         
        } else {
            $tn = time();
            $id = IdMakerService::make(IdMakerService::NAME_OF_DEVICE_BASE);
            $aliyunProjectInfo = AliyunProductService::fastGetByPk($pk);
            $addData = [
                'id' => $id,
                'pk' => $pk,
                'dn' => $dn,
                'iot_id' => $iotId,
                'serial_no' => '',
                'aliyun_project_id' => $aliyunProjectInfo ? $aliyunProjectInfo['aliyun_project_id'] : 0,
                'created' => $tn,
                'updated' => $tn,
            ]; 
            if(!empty($serverSite)){
                $addData['server_site'] = $serverSite;
            }
            $updateData['updated'] = $tn;
            self::upsert($addData, $updateData);
        }
        RedisLockService::releaseLock($lockName);
    }

    /**
     * 通过给定信息更新设备 
     * 此处有三方项目通过RabbitMQ调用  
     */
    public static function upsetByPkDn($params){

        $dn = $params['dn'];
        $pk = $params['pk'];
        $serialNo = $params['serial_no'];
        $iotId = $params['iot_id'];
        $userId = $params['user_id'];

        // 验证用户权限
        $user = UserBaseService::getByUserId($userId);
        if(empty($user)){ // 用户不存在  无权修改
            return;
        }
        $uid = $user['id'];
        $device = UserDeviceBindingService::getAllByUserAndIotIds($uid,[$iotId]);
        if(empty($device)){ // 用户不存在该绑定设备 
            return;
        }
        
        $serverSite = isset($params['server_site']) ? $params['server_site'] : '';
        $serialNo = $params['serial_no'];

        $updateData = [
            'serial_no' => $serialNo,
            'iot_id' => $iotId,
        ];

        if(!empty($serverSite)){
            $updateData['server_site'] = $serverSite;
        }
        $lockName = CommonCacheKeyService::getCacheKey(CommonCacheKeyService::CACHE_KEY_LOCK_OF_DEVICE_BASE, ['dn' => $dn]);
        if (!RedisLockService::getLock($lockName)) {
            throw new ApiException("请勿频繁操作 upsetDevice:" . $dn, ErrnoPlus::LOCKED_IS_EXISTS);
        }
        $origin = self::getByDn($dn,[
            'pk' => $pk,
        ]);

        $id = 0;
        if ($origin) { // 设备已存在
            $id = $origin['id'];
            $isNeedUpdate = false;
            $keys = array_keys($updateData);
            foreach($keys as $key){
                if($origin[$key] != $updateData[$key]){
                    $isNeedUpdate = true;
                    break;
                }
            }
            if($isNeedUpdate){
                self::update($id,$updateData);
                if ($origin['serial_no'] != $serialNo) {
                    NotifyDingTalkService::pushTextByAMQP("设备" . $dn . " 三元组信息变更 pk:" . $origin['pk'] . " => " . $pk . " serial_no:" . $origin['serial_no'] . "=>" . $serialNo);
                }
            }         
        } else {
            $tn = time();
            $id = IdMakerService::make(IdMakerService::NAME_OF_DEVICE_BASE);
            $aliyunProjectInfo = AliyunProductService::fastGetByPk($pk);
            $addData = [
                'id' => $id,
                'pk' => $pk,
                'dn' => $dn,
                'iot_id' => $iotId,
                'serial_no' => $serialNo,
                'aliyun_project_id' => $aliyunProjectInfo ? $aliyunProjectInfo['aliyun_project_id'] : 0,
                'created' => $tn,
                'updated' => $tn,
            ]; 
            if(!empty($serverSite)){
                $addData['server_site'] = $serverSite;
            }
            $updateData['updated'] = $tn;
            self::upsert($addData, $updateData);
        }
        RedisLockService::releaseLock($lockName);
    }

    /**
     * 更新设备信息
     * @param array $main 主设备信息  pk dn sn
     * @param array $children [dn1,dn2,...]
     */
    public static function upsetDevice($main, $children = [])
    {
        $dn = $main['dn'];
        $pk = $main['pk'];
        $subPk = isset($main['subPk']) ? $main['subPk'] : '';
        $serialNo = $main['sn'];
        $lockName = CommonCacheKeyService::getCacheKey(CommonCacheKeyService::CACHE_KEY_LOCK_OF_DEVICE_BASE, ['dn' => $dn]);
        if (!RedisLockService::getLock($lockName)) {
            throw new ApiException("请勿频繁操作 upsetDevice:" . $dn, ErrnoPlus::LOCKED_IS_EXISTS);
        }
        $origin = self::getByDn($dn);
        $id = 0;
        if ($origin) { // 设备已存在
            $id = $origin['id'];
            if ($origin['pk'] != $pk || $origin['serial_no'] != $serialNo) {
                NotifyDingTalkService::pushTextByAMQP("设备" . $dn . " 三元组信息变更 pk:" . $origin['pk'] . " => " . $pk . " serial_no:" . $origin['serial_no'] . "=>" . $serialNo);
                self::update($id, [
                    'pk' => $pk,
                    'serial_no' => $serialNo,
                ]);
            }
            if (empty($children) || empty($subPk)) {
                DeviceBaseChildService::delByPid($id);
            } else {
                DeviceBaseChildService::upsetByMainDevice($id, $subPk, $children);
            }
        } else {
            $tn = time();
            $id = IdMakerService::make(IdMakerService::NAME_OF_DEVICE_BASE);
            $aliyunProjectInfo = AliyunProductService::fastGetByPk($pk);
            $isAdd = self::upsert([
                'id' => $id,
                'pk' => $pk,
                'dn' => $dn,
                'serial_no' => $serialNo,
                'aliyun_project_id' => $aliyunProjectInfo ? $aliyunProjectInfo['aliyun_project_id'] : 0,
                'created' => $tn,
                'updated' => $tn,
            ], [
                'serial_no' => $serialNo,
                'updated' => $tn,
            ]);
            if (!$isAdd) { // 不是新增时
                $origin = self::getByDn($dn);
                $id = $origin['id'];
            }
            if (empty($children) || empty($subPk)) {

                // self::delByFilter(['pid' => $id]);

            } else {
                // self::upsetChildDevice($id, $subPk, $children);
            }
        }
        RedisLockService::releaseLock($lockName);

        AmqpService::simplePush(
            [
                'service' => 'app\\service\\DeviceBaseService@async',
                'params' => [
                    $id
                ],
             ]
        );

        // MQService::push([
        //     'service' => 'app\\service\\DeviceBaseService@async',
        //     'params' => [
        //          $id
        //     ],
        //  ], MQService::CHANNEL_OF_ACCOUNT);
    }
   

    public static function getDetailInfo($id)
    {
        $base = self::getBase($id);
        $children = self::getAllChildren($id);
        $base['children'] = $children;
        return $base;
    }

    /**
     * 同步设备信息
     */
    public static function async($id,$forceUpdate = false){
        $device = self::getBase($id);
        if(empty($device)){
            return null;
        }
        $pk = $device['pk'];
        $dn = $device['dn'];
        // 更新一下时间  避免重复更新同一个设备
        $tn = time();
        $project = AliyunProjectService::fastGetById($device['aliyun_project_id']);
        if(empty($project)){
            self::update($id,[
                'updated' => $tn,
            ]);
            return null;
        }
        $isUpdated = false;
        $serverSite = $device['server_site'];
        if(empty($serverSite) || $forceUpdate){
            $aliyun = AliyunService::instance($project['project_key'], 'CN');
            $regionInfo = $aliyun->getRawThingRegoin($pk, $dn);
            if ($regionInfo) {
                $region = AliyunService::getRegionByLocation($regionInfo);
                if($region !== $serverSite){
                    self::update($id,[
                        'server_site' => $region,
                    ]);
                    $serverSite = $region;
                    $isUpdated = true;
                }
            }
        }

        if(empty($device['iot_id']) || $forceUpdate) {
            $aliyun = AliyunService::instance($project['project_key'], $serverSite);
            $thingInfo = $aliyun->getRawThingInfo(null, $pk, $dn);
            if ($thingInfo) {
                if($device['iot_id'] !== $thingInfo['iotId']) {
                    self::update($device['id'], [
                        'iot_id' => $thingInfo['iotId'],
                    ]);
                    $isUpdated = true;
                }
            }
        }
        if(!$isUpdated){
            self::update($id,[
                'updated' => $tn,
            ]);
        }
        return $device;
    }

    
    /**
     * 页面查询条件
     */
    public static function buildCondition($filter)
    {
        $res = [];
        if (isset($filter['pk']) && !empty($filter['pk'])) {
            $res['pk'] = ['like', '%' . $filter['pk'] . '%'];
        }
        if (isset($filter['dn']) && !empty($filter['dn'])) {
            $res['dn'] = ['like', '%' . $filter['dn'] . '%'];
        }
        if (isset($filter['iot_id']) && !empty($filter['iot_id'])) {
            $res['iot_id'] = ['like', '%' . $filter['iot_id'] . '%'];
        }
        if (isset($filter['serial_no']) && !empty($filter['serial_no'])) {
            $res['serial_no'] = ['like', '%' . $filter['serial_no'] . '%'];
        }
        if (isset($filter['pid']) && is_numeric($filter['pid'])) {
            $res['pid'] = $filter['pid'];
        }
        return $res;
    }
}
